package com.alibaba.citrus.ots.application.report.ability.facade.job;

import com.alibaba.citrus.ots.application.report.ability.repository.BaseDataQueryRepository;
import com.alibaba.citrus.ots.application.report.ability.repository.CustomerStatementReportWriteRepository;
import com.alibaba.citrus.ots.application.report.ability.utils.DomUtil;
import com.alibaba.citrus.ots.common.annotation.FacadeInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.DateUtils;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcorder.model.dto.OrganizationSDO;
import com.epoch.app.crplatformenhance.api.customersalescopequery.dto.QuerySaleScopeByIdRequest;
import com.epoch.app.crplatformenhance.api.customersalescopequery.dto.QuerySaleScopeListByRelationIdRequest;
import com.epoch.app.crplatformenhance.api.customersalescopequery.service.CustomerSaleScopeQueryService;
import com.epoch.app.crplatformenhance.enums.OrganizationTypeEnum;
import com.epoch.app.crplatformenhance.sdo.CustomerSaleScopeSDO;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mncustomerstatement.dto.QueryRequest;
import com.epoch.app.otsapplicationadaptersdk.sapv2.mncustomerstatement.service.MnCustomerStatementService;
import com.epoch.app.otsapplicationreportsdk.contants.OtsApplicationReportSdkConstants;
import com.epoch.app.otsapplicationreportsdk.customerstatementwrite.dto.GenerateCustomerStatementReportJobRequest;
import com.epoch.app.otsapplicationreportsdk.customerstatementwrite.service.CustomerStatementWriteService;
import com.epoch.app.otsapplicationreportsdk.model.dto.CustomerStatementCallbackRequest;
import com.epoch.app.otsapplicationreportsdk.model.dto.CustomerStatementReportSDO;
import com.epoch.app.otsapplicationreportsdk.model.dto.QueryCustomerStatementReportRequest;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author zhoubc
 * @description: TODO
 * @date 2023/9/28 17:25
 */
@Primary
@Component
public class CustomerStatementWriteServiceJob implements CustomerStatementWriteService {
    private static Log log = Log.getLogger(CustomerStatementWriteServiceJob.class);

    @Resource
    CustomerStatementReportWriteRepository customerStatementReportWriteRepository;

    @Resource
    CustomerSaleScopeQueryService customerSaleScopeQueryService;

    @Resource
    BaseDataQueryRepository baseDataQueryRepository;

    @Resource
    MnCustomerStatementService mnCustomerStatementService;

    @Resource
    EpochCacheService epochCacheService;

    @Override
    @FacadeInvoker
    public Result<Void> callback(CustomerStatementCallbackRequest customerStatementCallbackRequest) {
        if (CollectionUtils.isEmpty(customerStatementCallbackRequest.getData())) {
            log.warn("CustomerStatementReportService_callback_data_is_null={}", JSON.toJSONString(customerStatementCallbackRequest));
            return Result.success(null);
        }

        List<CustomerStatementReportSDO> filterInvoiceList = customerStatementCallbackRequest.getData().stream().filter(x->"应收单据".equals(x.getDocName())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(filterInvoiceList)){
            throw new FacadeException("OTS-01-010-01-15-018");
        }
        CustomerStatementReportSDO sdo = filterInvoiceList.get(0);

        String yearMonth = invoiceDate2YearMonthConvert(sdo.getInvoiceDate());

        Integer deleteCount = customerStatementReportWriteRepository.batchDelete(sdo.getSalesOrganizationCode(),sdo.getChannelCode(),sdo.getCustomerCode(),sdo.getProfitCenter(),yearMonth);
        log.info("CustomerStatementReportService_callback|batchDelete_success_count={}",deleteCount);

        Integer insertCount = customerStatementReportWriteRepository.batchCreate(customerStatementCallbackRequest.getData(),yearMonth);
        log.info("CustomerStatementReportService_callback|batchCreate_success_count={}", insertCount);

        //释放请求锁
        Boolean b = removeSubmitLock(sdo, DateUtils.parse(yearMonth));

        return Result.success(null);
    }

    @Override
    @FacadeInvoker
    public Result<String> generateCustomerStatementReportJob(GenerateCustomerStatementReportJobRequest generateCustomerStatementReportJobRequest) {
        Date queryDate = new Date();

        if (StringUtils.isNotBlank(generateCustomerStatementReportJobRequest.getDate())) {
            try {
                queryDate = DateUtils.parse(generateCustomerStatementReportJobRequest.getDate());
            } catch (Exception e) {
                return Result.fail("-1","请输入的正确的日期格式：yyyy-MM-dd");
            }
        }

        //查询范围配置：销售组织
        String salesOrgCodes = OtsApplicationReportSdkConstants.CUSTOMER_STATEMENT_JOB_PULL_ORG();
        if (StringUtils.isBlank(salesOrgCodes)) {
            return Result.success(null);
        }
        String[] array = salesOrgCodes.split(",|，");
        Map<String, OrganizationSDO> salesOrgMap = baseDataQueryRepository.batchQueryOrganizationByOutCodes(Lists.newArrayList(array));
        log.info("CustomerStatementReportService_generateCustomerStatementReportJob_salesOrgs={}", JSONObject.toJSONString(salesOrgMap));

        Integer customerStat = 0;
        for (Map.Entry<String, OrganizationSDO> m : salesOrgMap.entrySet()) {
            //查询销售组织下已关联客户方负责人的售达方
            QuerySaleScopeListByRelationIdRequest querySaleScopeListRequest = new QuerySaleScopeListByRelationIdRequest();
            querySaleScopeListRequest.setRelatedOrganizationId(m.getValue().getId());
            querySaleScopeListRequest.setRelatedOrganizationType(OrganizationTypeEnum.SALES_ORGANIZATION.getCode());
            querySaleScopeListRequest.setStatus(1);
            Result<List<CustomerSaleScopeSDO>> customerSaleScopeResult = customerSaleScopeQueryService.querySaleScopeListByRelationId(querySaleScopeListRequest);
            if (customerSaleScopeResult==null || CollectionUtils.isEmpty(customerSaleScopeResult.getResult())) {
                continue;
            }
            log.info("CustomerStatementReportService_generateCustomerStatementReportJob_querySaleScopeListByRelationId_req={}，result_total={}", JSONObject.toJSONString(querySaleScopeListRequest),customerSaleScopeResult.getTotal());

            //分批次批量调用SAP客户对账单接口
            List<List<CustomerSaleScopeSDO>> partitionCustomerSaleScopeSDO = Lists.partition(customerSaleScopeResult.getResult(), 20);
            for (List<CustomerSaleScopeSDO> customerList : partitionCustomerSaleScopeSDO) {

                for (CustomerSaleScopeSDO customer: customerList) {
                    customer.setOrgSaleOrganizationCode(m.getValue().getCode());

                    //判断是否重复请求
                    if (StringUtils.isNotBlank(fetchSubmitLock(customer,queryDate))) {
                        log.warn("CustomerStatementReportService_generateCustomerStatementReportJob_repeated_request,customer={},queryDate={}",JSONObject.toJSONString(customer),DateUtils.toDateStr(queryDate,DateUtils.DATE_FORMAT));
                        continue;
                    }
                    this.requestCustomerStatementQuery(customer,queryDate);
                    customerStat++;
                }

                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        return Result.success(customerStat.toString());
    }

    @Override
    @FacadeInvoker
    public Result<Void> updateCustomerStatementReport(QueryCustomerStatementReportRequest queryCustomerStatementReportRequest) {
        if (StringUtils.isBlank(queryCustomerStatementReportRequest.getCustomerId()) && StringUtils.isBlank(queryCustomerStatementReportRequest.getCustomerCode())) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-012"));
        }
        if (queryCustomerStatementReportRequest.getQueryDate() == null) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-013"));
        }

        QuerySaleScopeByIdRequest querySaleScopeByIdRequest = QuerySaleScopeByIdRequest.builder().id(queryCustomerStatementReportRequest.getCustomerId()).build();
        Result<CustomerSaleScopeSDO> customerSaleScopeResult = customerSaleScopeQueryService.querySaleScopeById(querySaleScopeByIdRequest);
        if (customerSaleScopeResult == null || Objects.isNull(customerSaleScopeResult.getResult())) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-015"));
        }
        CustomerSaleScopeSDO customerSaleScopeSDO = customerSaleScopeResult.getResult();
        List<OrganizationSDO> customerSalesOrgs = baseDataQueryRepository.batchQueryOrganizationGetList(Lists.newArrayList(customerSaleScopeSDO.getOrgSaleOrganizationCode()));
        if(CollectionUtils.isEmpty(customerSalesOrgs)){
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-017"));
        }
        String customerSalesOrgCode = customerSalesOrgs.get(0).getCode();
        customerSaleScopeSDO.setOrgSaleOrganizationCode(customerSalesOrgCode);

        //查询范围配置：销售组织   客户销售组织在不在配置里
        String salesOrgCodes = OtsApplicationReportSdkConstants.CUSTOMER_STATEMENT_JOB_PULL_ORG();
        if (StringUtils.isBlank(salesOrgCodes)) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-016",customerSalesOrgCode));
        }
        String[] array = salesOrgCodes.split(",|，");
        if (!Lists.newArrayList(array).contains(customerSalesOrgCode)) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-016",customerSalesOrgCode));
        }

        //判断是否重复请求
        if (StringUtils.isNotBlank(fetchSubmitLock(customerSaleScopeSDO,queryCustomerStatementReportRequest.getQueryDate()))) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-019"));
        }

        //发送查询请求
        requestCustomerStatementQuery(customerSaleScopeSDO, queryCustomerStatementReportRequest.getQueryDate());

        return Result.success(null,"数据已经请求更新，请稍后刷新页面进行最新数据查询");
    }

    private void requestCustomerStatementQuery(CustomerSaleScopeSDO customer, Date queryDate){
        String year = DomUtil.getYear(queryDate);
        String month = String.valueOf(DomUtil.getMonthNum(queryDate));

        QueryRequest queryRequest = new QueryRequest();
        queryRequest.setSalesOrganizationCode(customer.getOrgSaleOrganizationCode());
        queryRequest.setChannelCode(customer.getChannelCode());
        queryRequest.setCustomerCode(customer.getCustomerCode());
        queryRequest.setProfitCenter("1000");
        queryRequest.setYear(year);
        queryRequest.setMonth(month);
        mnCustomerStatementService.query(queryRequest);
        log.info("CustomerStatementReportService_sendCustomerStatementQuery_req={}", JSONObject.toJSONString(queryRequest));

        String lockKey = fetchLockKey(customer,year,month);
        Long expiredTime = OtsApplicationReportSdkConstants.CUSTOMER_STATEMENT_JOB_REDIS_LOCK_MINUTES()!=null?OtsApplicationReportSdkConstants.CUSTOMER_STATEMENT_JOB_REDIS_LOCK_MINUTES():10L;
        epochCacheService.put(OtsApplicationReportSdkConstants.REDIS_CACHE_CODE(),lockKey,"1",expiredTime, TimeUnit.MINUTES);
    }

    private String fetchSubmitLock(CustomerSaleScopeSDO customer, Date queryDate){
        String lockKey = fetchLockKey(customer,DomUtil.getYear(queryDate),String.valueOf(DomUtil.getMonthNum(queryDate)));
        String value = epochCacheService.get(OtsApplicationReportSdkConstants.REDIS_CACHE_CODE(),lockKey);
        return value;
    }

    private Boolean removeSubmitLock(CustomerStatementReportSDO sdo, Date queryDate){
        CustomerSaleScopeSDO customer = new CustomerSaleScopeSDO();
        customer.setOrgSaleOrganizationCode(sdo.getSalesOrganizationCode());
        customer.setChannelCode(sdo.getChannelCode());
        customer.setCustomerCode(sdo.getCustomerCode());
        String lockKey = fetchLockKey(customer,DomUtil.getYear(queryDate),String.valueOf(DomUtil.getMonthNum(queryDate)));
        return epochCacheService.remove(OtsApplicationReportSdkConstants.REDIS_CACHE_CODE(),Lists.newArrayList(lockKey));
    }

    private String fetchLockKey(CustomerSaleScopeSDO customer,String year,String month){
        StringBuilder key = new StringBuilder();
        key.append(customer.getOrgSaleOrganizationCode())
                .append("#")
//                .append(customer.getChannelCode())
//                .append("#")
                .append(customer.getCustomerCode())
                .append("#")
                .append(year)
                .append("#")
                .append(month);
        return key.toString();
    }

    private String invoiceDate2YearMonthConvert(String invoiceDate){
        if (StringUtils.isBlank(invoiceDate)) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-011"));
        }

        try {
            Date date = DateUtils.string2Date(invoiceDate, DateUtils.PATTEN_YMD_PLAIN);
            return DomUtil.getStartOfMonth(date);
        } catch (Exception e) {
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-011"));
        }
    }

}
